Skip to main content

第56章 面向对象编程

面向对象编程(Object-Oriented Programming,简称OOP)是一种以"对象"为核心的编程范式,通过封装、继承、多态等特性,实现代码的模块化、复用性和可维护性。C++是支持面向对象编程的典型语言,其在C语言的基础上引入了类、对象、继承等概念,为复杂程序的设计提供了强大工具。

56.1 面向对象编程的基本概念

56.1.1 对象

对象是现实世界中实体的抽象,由属性(数据)和行为(操作数据的方法)组成。例如,"学生"对象的属性包括姓名、学号、成绩等,行为包括选课、考试等。在程序中,对象是类的实例,一个类可以创建多个对象。

56.1.2 类

类是对具有相同属性和行为的对象的抽象描述,是创建对象的模板。类定义了对象的属性(成员变量)和行为(成员函数),但不占用实际内存空间;对象是类的实例化,占用内存空间。例如,"学生类"定义了所有学生共有的属性和行为,而具体的学生(如"张三""李四")则是该类的对象。

56.1.3 面向对象的三大特性

  1. 封装(Encapsulation):将对象的属性和行为结合为一个整体,隐藏内部实现细节,仅通过公共接口与外部交互。
  2. 继承(Inheritance):子类可以继承父类的属性和行为,并可以添加新的属性和行为或重写父类的行为,实现代码复用和扩展。
  3. 多态(Polymorphism):同一操作作用于不同对象时,产生不同的执行结果。多态分为编译时多态(函数重载)和运行时多态(虚函数)。

56.2 类与对象的定义和使用

56.2.1 类的定义

#include <string>
using namespace std;

//学生类定义
class Student{
private:
//私有成员:仅类内部可访问
string name;
public:
//公共成员:类外部可访问(接口)
int id;
float score;

//构造函数:初始化对象
Student(string n,int i,float s){
name = n;
id = i;
score = s;
}

//成员函数:设置成绩(行为)
void setScore(float s){
if(s>=0&&s<=100){
score = s;
}
}

//成员函数:获取成绩(行为)
float getScore(){
return score;
}

//成员函数:显示信息(行为)
void showInfo(){
cout << "姓名:" << name << ",学号:" << id << ",成绩:" << score << endl;
}
};

56.2.2 访问控制符

C++通过访问控制符控制类成员的访问权限:

  1. private(私有):仅类内部可访问,隐藏实现细节。
  2. public(公共):类外部可直接访问,是类与外部交互的接口。
  3. protected(保护):类内部和子类可访问,用于继承场景。

56.2.3 对象的创建与使用

int main(){
//创建对象(实例化类)
Student stu1("张三", 1001, 90.5);
Student stu2("李四",1002, 85.0);

//调用成员函数(通过公共接口操作对象)
stu1.showInfo();
stu2.setScore(92.5);
stu2.showInfo();
return 0;
}

56.2.4 构造函数与析构函数

构造函数

与类名同名,无返回值,可重载,用于对象初始化。

class Person{
private:
string name;
int age;
public:
//无参构造函数
Person(){
name="未知";
age=0;
}
//带参构造函数
Person(string n,int a){
name = n;
age = a;
}
};

析构函数

类名前加~,无参数无返回值,不能重载,对象销毁时自动调用,用于释放资源。

class FileHandler {
private:
FILE* file;
public:
//构造函数:打开文件
FileHandler(string filename) {
file = fopen(filename.c_str(), "r");
}
//析构函数:释放文件资源
~FileHandler(){
if(file!= NULL){
fclose(file);
}
}
};

56.3 封装

56.3.1 封装实现逻辑

  1. 将成员变量设为private,禁止外部直接修改;
  2. 提供public成员函数作为读写接口,内部增加数据校验逻辑。
class BankAccount{
private:
double balance;//余额私有,外部不可直接修改
string accountId;
public:
BankAccount(string id, double initial) {
accountId = id;
if (initial>=0){
balance = initial;
}else{
balance=0;
}
}

//存款接口
void deposit(double amount) {
if (amount>0){
balance += amount;
}
}

//取款接口
bool withdraw(double amount) {
if (amount>0 && amount<= balance){
balance -= amount;
return true;
}
return false;
}

//查询余额接口
double getBalance(){
return balance;
}
};

56.3.2 封装优势

  1. 数据安全:限制外部随意修改,保证数据合法;
  2. 低耦合:内部逻辑修改时,外部调用代码无需改动;
  3. 功能集中:同一类的相关数据、操作统一管理。

56.4 继承

56.4.1 基础语法

格式:class 子类名 : 继承方式 父类名 继承方式:public、protected、private(默认private)

//父类
class Person {
protected:
string name;
int age;
public:
Person(string n, int a) : name (n), age (a) {}
void showBaseInfo(){
cout << "姓名:" << name << ",年龄:" << age << endl;
}
};

//子类 Student 公有继承 Person
class Student : public Person {
private:
int studentId;
public:
//子类构造函数,调用父类构造初始化
Student(string n, int a, int id) : Person(n, a), studentId(id) {}

void showStudentInfo(){
showBaseInfo();
cout << "学号:" << studentId << endl;
}
};

56.4.2 继承权限对照表

父成员public继承protected继承private继承
publicpublicprotectedprivate
protectedprotectedprotectedprivate
private子类不可访问子类不可访问子类不可访问

56.4.3 方法重写(Override)

父类声明virtual虚函数,子类定义同名同参函数完成重写,运行时多态基础。

class Animal {
public:
virtual void makeSound(){
cout<<"动物发出声音"<<endl;
}
};

class Dog : public Animal {
public:
void makeSound() override{
cout<<"汪汪汪"<<endl;
}
};

class Cat : public Animal {
public:
void makeSound() override{
cout<<"喵喵喵"<<endl;
}
};

56.4.4 继承优势

  1. 代码复用:直接复用父类已有属性与函数;
  2. 层次化设计:清晰描述"is-a"关系;
  3. 可扩展:新增功能仅写子类,不改动原有代码。

56.5 多态

56.5.1 编译时多态(函数重载)

同一类中同名函数,参数数量/类型不同,编译区分调用。

class Calculator {
public:
int add(int a,int b){
return a+b;
}
double add(double a,double b){
return a+b;
}
int add(int a,int b,int c){
return a+b+c;
}
};

int main(){
Calculator calc;
calc.add(1, 2);
calc.add(1.5, 2.5);
calc.add(1, 2, 3);
return 0;
}

56.5.2 运行时多态(虚函数)

父类指针/引用指向子类对象,自动执行子类重写的虚函数。

int main(){
Animal* animal1 =new Dog();
Animal* animal2 = new Cat;
animal1->makeSound();
animal2->makeSound();
delete animal1;
delete animal2;
return 0;
}

实现条件:

  1. 父类函数加virtual;
  2. 子类同名重写;
  3. 使用父类指针/引用操作子类实例。

56.5.3 多态优势

统一接口适配多种实现,新增子类无需修改上层调用代码,符合开闭原则。

56.6 其他重要概念

56.6.1 抽象类与纯虚函数

包含纯虚函数virtual 函数() = 0的类为抽象类,无法实例化,强制子类实现全部纯虚函数。

//抽象类
class Shape {
public:
virtual double getArea() = 0;
virtual double getPerimeter() = 0;
};

//子类必须实现两个纯虚函数
class Circle : public Shape {
private:
double radius;
public:
Circle (double r): radius(r) {}
double getArea() override {
return 3.14 * radius * radius;
}
double getPerimeter() override {
return 2* 3.14* radius;
}
};

56.6.2 友元

friend关键字允许外部函数/类访问当前类私有成员,破坏封装,仅特殊场景使用。

class Point {
private:
int x, y;
public:
Point(int x, int y):x(x),y(y) {}
//声明友元函数
friend void printPoint (Point p);
};

//友元可访问私有x、y
void printPoint (Point p){
cout << "(" << p.x << "," << p.y <<")"<< endl;
}

56.63 this指针

成员函数隐含this指针,指向当前调用对象,区分局部变量与成员变量。

class Person {
private:
string name;
public:
void setName(string name) {
this->name=name;
}
};

56.7 面向对象编程的优势

  1. 模块化:每个类独立负责一类功能,团队协作更清晰;
  2. 复用性:继承、类实例化实现代码复用;
  3. 可维护:封装隔离内部实现,修改不影响外部;
  4. 可扩展:多态、继承便于新增业务逻辑。